﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Xml;
using System.Xml.Serialization;
using DoodleLabyrinthLogic.Base;
using DoodleLabyrinthLogic.Item;

namespace DoodleLabyrinthLogic.Character
{
    public abstract class BaseCharacter
    {
        private readonly Guid _id;
        public Guid ID
        {
            get { return _id; }
        }
        
        private readonly string _name;
        public string Name
        {
            get { return _name; }
        }

        private readonly string _description;
        public string Description
        {
            get { return _description; }
        }

        private readonly int _level;
        public int Level
        {
            get { return _level; }
        }

        private readonly int _baseMeleeDefense;
        public virtual int MeleeDefense
        {
            get
            {
                int meleeDefense = _baseMeleeDefense;

                foreach (BaseItem item in _equipedItems)
                {
                    if (item.IsEquipable)
                    {
                        foreach (ObjectModifier modifier in item.ObjectModifiers)
                        {
                            meleeDefense += modifier.MeleeDefenseModifier;
                        }
                    }
                }

                return meleeDefense;
            }
        }

        private readonly int _baseMagicDefense;
        public virtual int MagicDefense
        {
            get
            {
                int magicDefense = _baseMagicDefense;

                foreach (BaseItem item in _equipedItems)
                {
                    if (item.IsEquipable)
                    {
                        foreach (ObjectModifier modifier in item.ObjectModifiers)
                        {
                            magicDefense += modifier.MagicDefenseModifier;
                        }
                    }
                }

                return magicDefense;
            }
        }

        private readonly int _baseAgility;
        public virtual int Agility
        {
            get
            {
                int agility = _baseAgility;

                foreach (BaseItem item in _equipedItems)
                {
                    if (item.IsEquipable)
                    {
                        foreach (ObjectModifier modifier in item.ObjectModifiers)
                        {
                            agility += modifier.AgilityModifier;
                        }
                    }
                }

                return agility;
            }
        }

        private readonly int _baseMeleeDamage;
        public virtual int MeleeDamage
        {
            get
            {
                int meleeDamage = _baseMeleeDamage;

                foreach (BaseItem item in _equipedItems)
                {
                    if(item is Weapon)
                    {
                        meleeDamage += ((Weapon) item).MeleeDamage;
                    }

                    if (item.IsEquipable)
                    {
                        foreach (ObjectModifier modifier in item.ObjectModifiers)
                        {
                            meleeDamage += modifier.MeleeDamageModifier;
                        }
                    }
                }

                return meleeDamage;
            }
        }

        private readonly int _baseMagicDamage;
        public virtual int MagicDamage
        {
            get
            {
                int magicDamage = _baseMagicDamage;

                foreach (BaseItem item in _equipedItems)
                {
                    if (item is Weapon)
                    {
                        magicDamage += ((Weapon)item).MeleeDamage;
                    }

                    if (item.IsEquipable)
                    {
                        foreach (ObjectModifier modifier in item.ObjectModifiers)
                        {
                            magicDamage += modifier.MagicDamageModifier;
                        }
                    }
                }

                return magicDamage;
            }
        }

        private readonly int _baseHealth;
        public virtual int MaximumHealth
        {
            get
            {
                int maximumHealth = _baseHealth;

                foreach (BaseItem item in _equipedItems)
                {
                    if (item.IsEquipable)
                    {
                        foreach (ObjectModifier modifier in item.ObjectModifiers)
                        {
                            maximumHealth += modifier.HealthModifier;
                        }
                    }
                }

                return maximumHealth;
            }
        }

        private readonly int _baseMana;
        public virtual int MaximumMana
        {
            get
            {
                int maximumMana = _baseMana;

                foreach(BaseItem item in _equipedItems)
                {
                    if(item.IsEquipable)
                    {
                        foreach(ObjectModifier modifier in item.ObjectModifiers)
                        {
                            maximumMana += modifier.ManaModifier;
                        }
                    }
                }

                return maximumMana;
            }
        }

        private int _currentHealth;
        public int CurrentHealth 
        { 
            get
            {
                if (_currentHealth <= 0 && OnCharacterDeath != null)
                {
                    OnCharacterDeath();
                }

                return _currentHealth;
            }
          }
        
        private readonly int _currentMana;
        public int CurrentMana { get { return _currentMana; } }

        private readonly List<BaseItem> _equipedItems = new List<BaseItem>();
        public List<BaseItem> InventoryItems = new List<BaseItem>();

        private delegate void OnCharacterDeathHandler();
        private event OnCharacterDeathHandler OnCharacterDeath;

        public Location CurrentLocation {get;set;}

        protected BaseCharacter (
            Guid id,
            string name,
            string description,
            int baseMeleeDefense,
            int baseMagicDefense,
            int baseAgility,
            int baseMeleeDamage,
            int baseMagicDamage,
            int baseHealth,
            int baseMmana,
            int level
            )
        {
            _baseMeleeDefense = baseMeleeDefense;
            _baseMagicDefense = baseMagicDefense;
            _baseAgility = baseAgility;
            _baseMeleeDamage = baseMeleeDamage;
            _baseMagicDamage = baseMagicDamage;
            _baseHealth = baseHealth;
            _baseMana = baseMmana;

            _level = level;

            _currentHealth = baseHealth;
            _currentMana = baseMmana;

            _id = id;
            _name = name;
            _description = description;

            OnCharacterDeath -= HandleOnCharacterDeath;
            OnCharacterDeath += HandleOnCharacterDeath;
        }

        private void HandleOnCharacterDeath()
        {
            HandleCharacterDeath();
        }

        protected virtual void HandleCharacterDeath()
        {
            
        }

        public void Attack(BaseCharacter target)
        {
            int totalDamage = 0;

            int meleeDamage = target.MeleeDefense - MeleeDamage;
            int magicDamage = target.MagicDefense - MagicDamage;

            if(meleeDamage < 0 && magicDamage < 0)
            {
                totalDamage += meleeDamage + magicDamage;
            }
            else if (magicDamage < 0)
            {
                totalDamage = magicDamage;
            }
            else if (meleeDamage < 0)
            {
                totalDamage = meleeDamage;
            }

            target.AssignDamage(totalDamage);
        }

        public void AssignDamage(int damageAmount)
        {
            _currentHealth += damageAmount;

            if(_currentHealth <= 0 && OnCharacterDeath != null)
            {
                OnCharacterDeath();
            }
        }

        public virtual XmlDocument ToXML()
        {
            StringBuilder stringBuilder = new StringBuilder();
            XmlWriter xmlWriter = XmlWriter.Create(stringBuilder);
            // Convert the object to XML data and put it in the stream
            XmlSerializer serializer = new XmlSerializer(typeof(BaseCharacter));
            serializer.Serialize(xmlWriter, this);

           XmlDocument xmlDocument = new XmlDocument();

            xmlDocument.LoadXml(stringBuilder.ToString());

            return xmlDocument;
        }
    }
}
